package com.education.aspect;

import com.alibaba.fastjson.JSONObject;
import com.education.auth.aspectannotation.BusinessDiary;
import com.education.auth.entity.BusinessDiaryVo;
import com.education.auth.entity.UserInfo;
import com.education.auth.utlis.JwtUtils;
import com.education.common.pojo.SysUserOther;
import com.education.common.utils.IpUtils;
import com.education.config.JwtProperties;
import com.education.welco.feign.DiaryFeifn;
import com.education.welco.pojo.User;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 日志保存Service
 *
 * @author liftsail
 */
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Aspect
@Component
@EnableConfigurationProperties(JwtProperties.class)//将JwtProperties注入到spring容器
public class BusinessDiaryAspect {

    private static final Logger log = LoggerFactory.getLogger(BusinessDiaryAspect.class);

    //获得jwt公钥
    @Autowired
    //@Qualifier(value = "JwtProperties1")
    private JwtProperties jwtProp;

    //调用日志接口
    @Autowired
    private DiaryFeifn diaryFeifn;


    @Pointcut(value = "@annotation(com.education.auth.aspectannotation.BusinessDiary)")
    public void pointCut() {
    }

    @Before(value = "pointCut() && args(..)")
    public void before(JoinPoint joinPoint) throws Exception {
        BusinessDiaryVo businessDiaryVO = new BusinessDiaryVo();
        String methodName = joinPoint.getSignature().getName();
        Method method = currentMethod(joinPoint, methodName);
        BusinessDiary BusinessDiary = method.getAnnotation(BusinessDiary.class);
        String cModelMethod = BusinessDiary.methodUrl();
        String record = BusinessDiary.record();
        String opeTypeName = BusinessDiary.opeTypeName();
        String opeTypeValue = BusinessDiary.opeTypeValue();
        //为日志实体类赋值
        businessDiaryVO.setMethodUrl(cModelMethod);
        businessDiaryVO.setMethodName(methodName);
        businessDiaryVO.setRecord(record);
        businessDiaryVO.setOpeTypeName(opeTypeName);
        businessDiaryVO.setOpeTypeValue(opeTypeValue);
        for (int i = 0; i < joinPoint.getArgs().length; i++) {
            //System.out.println(joinPoint.getArgs()[i]);
        }
        //System.out.println(joinPoint.getSignature().getName());
        Object[] obj = joinPoint.getArgs();
        if (null == obj || obj.length == 0) {
            return;
        }
        String parameter = null;
        for (Object o : obj) {
            if (o instanceof JSONObject) {
                parameter = o.toString();
            } /*else {
                parameter = JSON.toJSONString(o);
            }*/
        }
        if (null == parameter) {
            parameter = Arrays.toString(obj);
            // return;
        }

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest req = attributes.getRequest();
        businessDiaryVO.setIp(IpUtils.getIpAddr(req));
        businessDiaryVO.setUrl(req.getRequestURL().toString());
        businessDiaryVO.setParams(parameter);
        String terminal = req.getHeader("User-Agent");
        businessDiaryVO.setTerminal(null != terminal && terminal.contains("Windows NT") ? "0" : "1");// B端和C端

        /**
         * 1.有token
         *  token处理得到 用户id和用户name    根据是否有token判断操作类型
         */
        String token = req.getHeader("token");
        if (StringUtils.isNotEmpty(token) && StringUtils.isNotBlank(token)) {
            UserInfo userInfo = JwtUtils.getInfoFromToken(token, jwtProp.getPublicKey());
            long userId = userInfo.getId();
            String username = userInfo.getUsername();
            String userPhone = userInfo.getUserPhone();

            businessDiaryVO.setUserId(userId);
            businessDiaryVO.setUserName(username);
            businessDiaryVO.setUserPhone(userPhone);
            //操作类型（1.登录 2.其他）
            businessDiaryVO.setOpeType("2");
        } else {
            //操作类型（1.登录 2.其他）
            businessDiaryVO.setOpeType("1");
            /**
             * 2.没有token
             * 登录接口，从参数中获取参数
             */
            if (record.contains("登录")) {
                List<Object> objects = Arrays.asList(obj);
                //获得登录手机号
                User user = (User) objects.get(0);
                //根据用户手机号进行查询用户信息
                SysUserOther userq = diaryFeifn.queryUserByUserPhone(user.getSysPhone());
                //判断该用户是否存在 ,不存在不进行日志记录
                if (Objects.isNull(userq.getId())) {
                    return;
                }
                businessDiaryVO.setRecord("用户名:" + userq.getSysRelname() + "," + record);
                businessDiaryVO.setUserPhone(user.getSysPhone());
                businessDiaryVO.setUserId(userq.getId().longValue());
                businessDiaryVO.setUserName(userq.getSysRelname());
            }
        }

        //调用user-service的日志新增服务
        int diaryAdd = diaryFeifn.diaryAdd(businessDiaryVO);
    }

    /**
     * 获取Ip地址
     *
     * @param request 请求参数
     * @return 返回值
     */
    private String getIpAdrress(HttpServletRequest request) {
        String Xip = request.getHeader("X-Real-IP");
        String XFor = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = XFor.indexOf(",");
            if (index != -1) {
                return "0" + XFor.substring(0, index);
            } else {
                return "0" + XFor;
            }
        }
        XFor = Xip;
        if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
            return XFor;
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getRemoteAddr();
        }
        return XFor;
    }


    private Method currentMethod(JoinPoint joinPoint, String methodName) {
        Method[] methods = joinPoint.getTarget().getClass().getMethods();
        Method resultMethod = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                resultMethod = method;
                break;
            }
        }
        return resultMethod;
    }
}
